package com.appcan.base;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.Query;



public abstract class UfidaDAO {

	private EntityManager manager;

	public UfidaDAO(EntityManager manager) {
		this.manager = manager;
	}

	protected EntityManager getManager() {
		return manager;
	}

	protected void setManager(EntityManager manager) {
		this.manager = manager;
	}

	protected void setParams(Map<String, Object> paramsValues, Query query) {
		if (paramsValues != null && !paramsValues.isEmpty()) {
			Iterator<Map.Entry<String, Object>> it = paramsValues.entrySet()
					.iterator();
			while (it.hasNext()) {
				Map.Entry<String, Object> entry = it.next();
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
	}

	@SuppressWarnings("unchecked")
	protected List queryByPage(String ql, Map<String, Object> paramsValues,
			int pagesize, int currentpage, boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, paramsValues);
		} else {
			query = this.createNativeQuery(ql, paramsValues);
		}
		List list = query.setMaxResults(pagesize).setFirstResult(currentpage)
				.getResultList();
		// 分离内存中受EntityManager管理的实体bean，让VM进行垃圾回收
		this.getManager().clear();
		return list;
	}

	@SuppressWarnings("unchecked")
	protected List queryByPage(String ql, int pagesize, int currentpage,
			boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, null);
		} else {
			query = this.createNativeQuery(ql, null);
		}
		List list = query.setMaxResults(pagesize).setFirstResult(
				currentpage * pagesize).getResultList();
		// 分离内存中受EntityManager管理的实体bean，让VM进行垃圾回收
		this.getManager().clear();
		return list;
	}

	/**
	 * 去除hql的orderby 子句，用于pagedQuery.
	 * 
	 * @see #pagedQuery(String, int, int, Object[])
	 */
	private static String removeOrders(String hql) {
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*",
				Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 去除hql的select 子句，未考虑union的情况,用于pagedQuery.
	 * 
	 * @see #pagedQuery(String, int, int, Object[])
	 */
	private static String removeSelect(String hql) {
		int beginPos = hql.toLowerCase().indexOf("from");
		return hql.substring(beginPos);
	}

	/**
	 * 根据hql查询,直接使用HibernateTemplate的find函数.
	 * 
	 * @param values
	 *            可变参数,见{@link #createQuery(String,Object...)}
	 */
	public List find(String hql, Object... values) {
		List list = null;
		Query query = this.manager.createQuery(hql);
		if (values != null && values.length >= 1) {
			for (int i =1; i <=values.length; i++) {
				query.setParameter(i, values[i-1]);
			}
		}
		list = query.getResultList();
		return list;
	}
	public List findsql(String sql) {
		List list = null;
		Query query = this.manager.createNativeQuery(sql);
		list = query.getResultList();
		return list;
	}

	/**
	 * 创建Query对象.
	 * 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
	 * 留意可以连续设置,如 dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
	 * 调用方式如下：
	 * 
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQueryhql(String hql, Object... values) {
		Query query = this.manager.createQuery(hql);
		for (int i = 1; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	protected Page pagedQuery(String hql, int pageNo, int pageSize,
			Object... values) {

		// Count查询
		String countQueryString = " select count (*) "
				+ removeSelect(removeOrders(hql));
		List countlist = find(countQueryString, values);
		long totalCount = (Long) countlist.get(0);

		if (totalCount < 1) {
			return new Page();
		}

		// 实际查询返回分页对象
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		Query query = createQueryhql(hql, values);
		List list = query.setFirstResult(startIndex).setMaxResults(pageSize)
				.getResultList();

		return new Page(startIndex, totalCount, pageSize, list);
	}
	public Page pagedQueryBySQL(String sql, int pageNo, int pageSize) {

		// Count查询
		String countQueryString = " select count (*) "
				+ removeSelect(removeOrders(sql));
		List countlist = findsql(countQueryString);
		long totalCount = (Integer) countlist.get(0);

		if (totalCount < 1) {
			return new Page();
		}

		// 实际查询返回分页对象
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		List list = this.manager.createNativeQuery(sql).setFirstResult(startIndex).setMaxResults(pageSize).getResultList();

		return new Page(startIndex, totalCount, pageSize, list);
	}

	@SuppressWarnings("unchecked")
	protected List query(String ql, Map<String, Object> paramsValues,
			boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, paramsValues);
		} else {
			query = this.createNativeQuery(ql, paramsValues);
		}
		return query.getResultList();
	}

	protected int getResultCount(String ql, Map<String, Object> paramsValues,
			boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, paramsValues);
		} else {
			query = this.createNativeQuery(ql, paramsValues);
		}
		// List result = query.getResultList();
		// return result == null || result.isEmpty() ? 0 : ((Long)
		// result.get(0)).intValue();
		Object result = query.getSingleResult();
		return result == null ? 0 : Integer.valueOf(String.valueOf(result));
	}

	@SuppressWarnings("unchecked")
	protected int getResultCount(String ql, boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, null);
		} else {
			query = this.createNativeQuery(ql, null);
		}
		List result = query.getResultList();
		return result == null || result.isEmpty() ? 0 : ((Long) result.get(0))
				.intValue();
	}

	protected Query createQuery(String ejb3ql, Map<String, Object> paramsValues) {
		Query query = this.getManager().createQuery(ejb3ql);
		if (paramsValues != null && !paramsValues.isEmpty()) {
			this.setParams(paramsValues, query);
		}
		return query;
	}

	protected Query createNativeQuery(String sql,
			Map<String, Object> paramsValues) {
		Query query = this.manager.createNativeQuery(sql);
		if (paramsValues != null && !paramsValues.isEmpty()) {
			this.setParams(paramsValues, query);
		}
		return query;
	}

	protected int batchAction(String ql, Map<String, Object> paramsValues,
			boolean isEjb3ql) {
		Query query = null;
		if (isEjb3ql) {
			query = createQuery(ql, paramsValues);
		} else {
			query = this.createNativeQuery(ql, paramsValues);
		}
		return query.executeUpdate();
	}

	protected int batchAction(String ql, boolean isEjb3ql) {
		return this.batchAction(ql, null, isEjb3ql);
	}

	protected String handleEjb3ql(StringBuffer ejb3qlBuffer) {
		String ejb3ql = null;
		if (ejb3qlBuffer.toString().indexOf("AND") == -1) {
			ejb3ql = ejb3qlBuffer.substring(0, ejb3qlBuffer
					.lastIndexOf("WHERE"));
		} else {
			ejb3ql = ejb3qlBuffer.substring(0, ejb3qlBuffer.lastIndexOf("AND"));
		}
		return ejb3ql;
	}

	@SuppressWarnings("unchecked")
	protected Object getObject(Class objClass, Long id) {
		return this.manager.find(objClass, id);
	}

	@SuppressWarnings("unchecked")
	protected void saveOrUpdate(List entitys) {
		if (entitys == null || entitys.isEmpty()) {
			return;
		}
		int index = 0;
		for (Object entity : entitys) {
			index++;
			Long id = findId(entity);
			if (id == null) {
				this.getManager().persist(entity);
			} else {
				this.update(id, entity);
			}
			if (index % 30 == 0) {
				this.getManager().flush();
			}
		}
	}
	protected abstract Long findId(Object entity);

	protected abstract void update(Long id, Object entity);
}
